#include "sdk.h"
#include "M_Code_auibook.h"
#include "M_Code_StyledTextCtrl.h"

inline int editorbase_RegisterId( int id ) {
  wxRegisterId( id );
  return id;
}

struct EditorBaseInternalData {
  EditorBaseInternalData( EditorBase* owner )
    : m_pOwner( owner ),
      m_DisplayingPopupMenu( false ),
      m_CloseMe( false ) {}
  EditorBase* m_pOwner;
  bool m_DisplayingPopupMenu;
  bool m_CloseMe;
};

const int EditorMaxSwitchTo = 255;
const int idSwitchFile1 = wxNewId();
const int idSwitchFileMax = editorbase_RegisterId( idSwitchFile1 + EditorMaxSwitchTo - 1 );
const int idCloseMe = wxNewId();
const int idCloseAll = wxNewId();
const int idCloseAllOthers = wxNewId();
const int idSaveMe = wxNewId();
const int idSaveAll = wxNewId();
const int idSwitchTo = wxNewId();
const long idGoogle = wxNewId();
const long idMsdn = wxNewId();
const long idCPlusPlusCom = wxNewId();

BEGIN_EVENT_TABLE( EditorBase, wxPanel )
  EVT_MENU_RANGE( idSwitchFile1, idSwitchFileMax, EditorBase::OnContextMenuEntry )
  EVT_MENU( idCloseMe, EditorBase::OnContextMenuEntry )
  EVT_MENU( idCloseAll, EditorBase::OnContextMenuEntry )
  EVT_MENU( idCloseAllOthers, EditorBase::OnContextMenuEntry )
  EVT_MENU( idSaveMe, EditorBase::OnContextMenuEntry )
  EVT_MENU( idSaveAll, EditorBase::OnContextMenuEntry )
  EVT_MENU( idGoogle, EditorBase::OnContextMenuEntry )
  EVT_MENU( idMsdn, EditorBase::OnContextMenuEntry )
  EVT_MENU( idCPlusPlusCom, EditorBase::OnContextMenuEntry )
END_EVENT_TABLE()

EditorBase::EditorBase( wxWindow* parent, const wxString& filename )
  : wxPanel( parent, -1 ),
    m_IsBuiltinEditor( false ),
    m_Shortname( _T( "" ) ),
    m_Filename( _T( "" ) ),
    m_WinTitle( filename ) {
  m_pData = new EditorBaseInternalData( this );
  Manager::Get()->GetEditorManager()->AddCustomEditor( this );
  InitFilename( filename );
  SetTitle( m_Shortname );
}

EditorBase::~EditorBase() {
  if( !Manager::Get()->IsAppShuttingDown() ) {
    Manager::Get()->GetEditorManager()->RemoveCustomEditor( this );
    CodeBlocksEvent event( cbEVT_EDITOR_CLOSE );
    event.SetEditor( this );
    event.SetString( m_Filename );
    Manager::Get()->GetPluginManager()->NotifyPlugins( event );
  }
  delete m_pData;
}
void EditorBase::InitFilename( const wxString& filename ) {
  if( filename.IsEmpty() ) {
    m_Filename = realpath( CreateUniqueFilename() );
  } else {
    m_Filename = realpath( filename );
  }
  wxFileName fname;
  fname.Assign( m_Filename );
  m_Shortname = fname.GetFullName();
}

wxString EditorBase::CreateUniqueFilename() {
  const wxString prefix = _T( "无题" );
  const wxString path = wxGetCwd() + wxFILE_SEP_PATH;
  wxString tmp;
  int iter = 0;
  while( true ) {
    tmp.Clear();
    tmp << path << prefix << F( _T( "%d" ), iter );
    if( !Manager::Get()->GetEditorManager()->GetEditor( tmp ) &&
        !wxFileExists( path + tmp ) ) {
      return tmp;
    }
    ++iter;
  }
}

const wxString& EditorBase::GetTitle() {
  return m_WinTitle;
}

void EditorBase::SetTitle( const wxString& newTitle ) {
  m_WinTitle = newTitle;
  int mypage = Manager::Get()->GetEditorManager()->FindPageFromEditor( this );
  if( mypage != -1 ) {
    Manager::Get()->GetEditorManager()->GetNotebook()->SetPageText( mypage, newTitle );
  }
  wxString toolTip = GetFilename();
  wxFileName fname( realpath( toolTip ) );
  NormalizePath( fname, wxEmptyString );
  toolTip = UnixFilename( fname.GetFullPath() );
  M_Code_Project* prj = Manager::Get()->GetProjectManager()->FindProjectForFile( toolTip, nullptr, false, true );
  if( prj ) {
    toolTip += _T( "\n项目: " ) + prj->GetTitle();
  }
  M_Code_AuiNotebook* nb = Manager::Get()->GetEditorManager()->GetNotebook();
  if( nb ) {
    int idx = nb->GetPageIndex( this );
    nb->SetPageToolTip( idx, toolTip );
    Manager::Get()->GetEditorManager()->MarkReadOnly( idx, IsReadOnly() || ( fname.FileExists() && !wxFile::Access( fname.GetFullPath(), wxFile::write ) ) );
  }
}

void EditorBase::Activate() {
  Manager::Get()->GetEditorManager()->SetActiveEditor( this );
}

bool EditorBase::QueryClose() {
  if( GetModified() && !wxGetKeyState( WXK_CONTROL ) ) {
    if( !Save() ) {
      return false;
    }
    SetModified( false );
  }
  return true;
}

bool EditorBase::Close() {
  Destroy();
  return true;
}

bool EditorBase::IsBuiltinEditor() const {
  return m_IsBuiltinEditor;
}

bool EditorBase::ThereAreOthers() const {
  return ( Manager::Get()->GetEditorManager()->GetEditorsCount() > 1 );
}

void EditorBase::DisplayContextMenu( const wxPoint& position, ModuleType type ) {
  bool noeditor = ( type != mtEditorManager );
  if( !OnBeforeBuildContextMenu( position, type ) ) {
    return;
  }
  wxMenu* popup = new wxMenu;
  if( !noeditor && wxGetKeyState( WXK_CONTROL ) ) {
    M_Code_StyledTextCtrl* control = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor()->GetControl();
    wxString text = control->GetSelectedText();
    if( text.IsEmpty() ) {
      const int pos = control->GetCurrentPos();
      text = control->GetTextRange( control->WordStartPosition( pos, true ), control->WordEndPosition( pos, true ) );
    }
    if( !text.IsEmpty() ) {
      popup->Append( idGoogle, _T( "网络搜索 \"" )  + text + _T( "\"" ) );
      popup->Append( idMsdn, _T( "MSDN搜索 \"" ) + text + _T( "\"" ) );
      popup->Append( idCPlusPlusCom, _T( "CplusPlus搜索 \"" ) + text + _T( "\"" ) );
    }
    lastWord = text;
    wxMenu* switchto = new wxMenu;
    int ID = idSwitchTo;
    m_SwitchTo.clear();
    for( int i = 0; i < EditorMaxSwitchTo && i < Manager::Get()->GetEditorManager()->GetEditorsCount(); ++i ) {
      EditorBase* other = Manager::Get()->GetEditorManager()->GetEditor( i );
      if( !other || other == this ) {
        continue;
      }
      ID = idSwitchFile1 + i;
      m_SwitchTo[ID] = other;
      switchto->Append( ID, ( other->GetModified() ? _T( "*" ) : wxEmptyString ) + other->GetShortName() );
    }
    if( !switchto->GetMenuItemCount() ) {
      delete switchto;
      switchto = nullptr;
    }
    popup->Append( idSwitchTo, _T( "切换到" ), switchto );
  } else if( !noeditor && wxGetKeyState( WXK_ALT ) ) {
  } else {
    if( type == mtOpenFilesList ) {
      popup->Append( idCloseMe, _T( "关闭" ) );
      popup->Append( idCloseAll, _T( "关闭全部" ) );
      popup->Append( idCloseAllOthers, _T( "互斥关闭" ) );
      popup->Append( idSaveMe, _T( "保存" ) );
      popup->Append( idSaveAll, _T( "保存全部" ) );
      popup->Enable( idSaveMe, GetModified() );
      bool hasOthers = ThereAreOthers();
      popup->Enable( idCloseAll, hasOthers );
      popup->Enable( idCloseAllOthers, hasOthers );
    }
    AddToContextMenu( popup, type );
    FileTreeData* ftd = new FileTreeData( nullptr, FileTreeData::ftdkUndefined );
    ftd->SetFolder( m_Filename );
    Manager::Get()->GetPluginManager()->AskPluginsForModuleMenu( type, popup, ftd );
    delete ftd;
  }
  wxPoint clientpos;
  if( position == wxDefaultPosition ) {
    M_Code_StyledTextCtrl* const control = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor()->GetControl();
    clientpos = control->PointFromPosition( control->GetCurrentPos() );
  } else {
    clientpos = ScreenToClient( position );
  }
  m_pData->m_DisplayingPopupMenu = true;
  PopupMenu( popup, clientpos );
  delete popup;
  m_pData->m_DisplayingPopupMenu = false;
  if( m_pData->m_CloseMe ) {
    Manager::Get()->GetEditorManager()->Close( this );
  }
}

void EditorBase::OnContextMenuEntry( wxCommandEvent& event ) {
  const int id = event.GetId();
  m_pData->m_CloseMe = false;
  if( id == idCloseMe ) {
    if( m_pData->m_DisplayingPopupMenu ) {
      m_pData->m_CloseMe = true;
    } else
    { Manager::Get()->GetEditorManager()->Close( this ); }
  } else if( id == idCloseAll ) {
    if( m_pData->m_DisplayingPopupMenu ) {
      Manager::Get()->GetEditorManager()->CloseAllInTabCtrlExcept( this );
      m_pData->m_CloseMe = true;
    } else
    { Manager::Get()->GetEditorManager()->CloseAllInTabCtrl(); }
  } else if( id == idCloseAllOthers ) {
    Manager::Get()->GetEditorManager()->CloseAllInTabCtrlExcept( this );
  } else if( id == idSaveMe ) {
    Save();
  } else if( id == idSaveAll ) {
    Manager::Get()->GetEditorManager()->SaveAll();
  } else if( id >= idSwitchFile1 && id <= idSwitchFileMax ) {
    EditorBase* const ed = m_SwitchTo[id];
    if( ed ) {
      Manager::Get()->GetEditorManager()->SetActiveEditor( ed );
    }
    m_SwitchTo.clear();
  } else {
    if( id == idGoogle ) {
      wxLaunchDefaultBrowser( wxString( _T( "http://www.baidu.com/s?wd=" ) ) << URLEncode( lastWord ) );
    } else if( id == idMsdn ) {
      wxLaunchDefaultBrowser( wxString( _T( "http://social.msdn.microsoft.com/Search/en-US/?query=" ) ) << URLEncode( lastWord ) << _T( "&ac=8" ) );
    } else if( id == idCPlusPlusCom ) {
      wxLaunchDefaultBrowser( wxString( _T( "http://www.cplusplus.com/search.do?q=" ) ) << URLEncode( lastWord ) );
    }
  }
}

bool EditorBase::IsContextMenuOpened() const {
  return m_pData->m_DisplayingPopupMenu;
}
